Troubleshooters.Com and Code Corner Present

Steve Litt's Perls of Wisdom:
Perl CGI Web Forms
(With Snippets)

Copyright (C) 1998, 2000 by Steve Litt


NOTE: If you're looking for the CGI source code to display man pages in a browser, it's at:
../../linux/quickhacks.htm#Manpagesformattedashtml.

Interfacing forms with CGI can be gruesome. Or it can be easy. This page gives you advice and tools to make form/CGI interfacing easy.

  1. Make sure you know all the info on the Perl Hello World page.
  2. Make the form.
  3. Get the form's output.
  4. Set up a batch file to edit/compile/test your cgi script.
  5. Test on the server.
See also: If your script writes a file.
Making a Form with CGI
 

Make the form.

I'd recommend the MS Frontpage editor, or any other tool that makes forms easy. Put all the fields you expect to have. Get the page pretty much the way you want it. Set the submit button's action to stdin.cgi. Then FTP the page up to your server.

Get the form's output.

  1. Put stdin.cgi on the server, in the same directory as the form. It's shown below. Modify as necessary for your server (probably just first line).
  2. #!/usr/bin/perl
    print "Content-type: text/html\n\n";
    print "Output of form. Copy next line into clipboard:<P>\n";
    while(<STDIN>)
      {
      chomp($_);
      print "$_<br>\n";
      }
    print "Copy previous line into clipboard<P>\n";
  3. Make it executable:

  4. chmod a+x stdin.cgi
  5. Use your browser to hit the form. Fill in all fields with recognizable and memorable info. Then click the submit button. A web page like this should appear. Note that the middle line has been truncated in this example to save space, but on your browser it might go on for hundreds or thousands of characters:
  6. Output of form. Copy next line into clipboard:
    
    OrganizationName=orgname&OrganizationType=Choose+closest+business+...
    Copy previous line into clipboard
  7. Highlight and copy the middle line, and paste it into an editor on your local machine. Save it as STD.IN. You'll work continuously with this file to refine the real CGI script for your form. You can repeat the procedures in this section to make different test files.

Set up a batch file to edit/compile/test your cgi script.

Here's the TESTFORM.BAT batch file:
 
set REQUEST_METHOD=POST
rem SET NEXT LINE TO LINE LENGTH OF FILE STD.IN
set CONTENT_LENGTH=2795
perl myscript.cgi < std.in > testform.htm
rem NEXT LINE RUNS YOUR BROWSER LOADING TESTFORM.HTM
e:\nsgold3\navigator\program\netscape.exe d:\at\perl\testform.htm

You might want to put it in a loop with an editor so you can have a continuous edit/compile/test environment.

Test on the server.

After your CGI script does just what you want, FTP it up to the proper directory on the server and make it executable with chmod a+x myscript.cgi.

On your machine, change the form's action from stdin.cgi to your cgi script (myscript.cgi in this example). FTP it up to the server.

Test with your browser, and troubleshoot as necessary.

If your script writes a file

If your script creates a file, you must make sure to change the access to the directory holding the file with:
chmod a+w mydirectory
Once the file is created, the file is owned by http or whatever, not by you. You can't delete it (except with a perlscript called from a web page). However, for securities sake, once it's created, you can deny write access to the directory with
chmod a-w mydirectory
The perlscript will still be able to write the file, because http (or whatever) owns it.
 

Making a Form With CGI

Here's about the simplest CGI form maker. Put it in hello.cgi, chmod it read and execute for all, and access it from a browser. You should see the words "Hello World" on the screen. Be sure to run the following command:
chmod a+rx hello.cgi
The first time you create this file, and any time you get a "forbidden" response.
 
#!/usr/bin/perl -w
# PUBLIC DOMAIN, NO WARRANTEE. USE AT YOUR OWN RISK

use strict;
print "Content-type: text/html\n\n";
print "<html><body>\n";
print "Hello World<p>\n";
print "</html></body>\n";

Once you have this file running, copy it to helloform.cgi and modify it by placing the form writing code in a subroutine. This is essential for future building:
 
#!/usr/bin/perl -w

# PUBLIC DOMAIN, NO WARRANTEE. USE AT YOUR OWN RISK

use strict;

sub MakePage()
  {
  print "Content-type: text/html\n\n";
  print "<html><body>\n";
  print "Hello World<br>\n";
  print "</html></body>\n";
  }

MakePage();

Note that stdin.cgi was coded earlier on this page, and outputs the form information in a raw form. Assuming you leave the field contents at their default "Hello World", the output after you click the submit button will appear as follows:
 
Output of form. Copy next line into clipboard:

TXhelloField=Hello+World&BXsub=Submit
Copy previous line into clipboard

You can see that controls are separated by ampersand (&) signs, and each control name is separated from its value by an equal sign (=). Also evident is that spaces are represented by plus signs. What you don't see in this example is that punctuation is represented by by a percent sign followed by a two hex digit representation of the character's ascii value. Place the string "<<??==%%>>" in the field, and the output now looks like this:
 
Output of form. Copy next line into clipboard:

TXhelloField=%3C%3C%3F%3F%3D%3D%25%25%3E%3E&BXsub=Submit
Copy previous line into clipboard

To explore the representation of various characters, copy helloform.cgi to testchars.cgi, which is coded as follows:
 
#!/usr/bin/perl -w


use strict;

sub MakeString()
  {
  my($string) = "";
  my($i);
  foreach $i (32..126)
    {
    $string .= chr($i) unless ($i == 34);
    }
  return($string);
  }

sub MakePage()
  {
  print "Content-type: text/html\n\n";
  print "<html><head><title>Hello World Form</title></head><body>\n";

  print "<center><big><big><big><strong>\n";
  print "Hello World Form<p>\n";
  print "</strong></big></big></big>\n";

  print "<FORM ACTION=\"./stdin.cgi\" METHOD=\"POST\">\n";
  print "The Field...<br>\n";
  print "<input type=\"text\" name=\"TXhelloField\" size=\"100\" \n";
  print "value=\"" . MakeString() . "\">\n";
  print "<INPUT type=\"submit\" name=\"BXsub\" value=\"Submit\">\n";
  print "</form>"; 

  print "</body></html>\n"; 
  }

MakePage();

Note the MakeString() function, which constructs a string consisting of all characters of decimal ascii values 32 (space) to 126 (~) except 34 (>), which would interfere with the html. After pressing the submit button, stdin.cgi shows the following output:
 
Output of form. Copy next line into clipboard:

TXhelloField=+%21%23%24%25%26%27%28%29*%2B%2C-.%2F0123456789%3A%3B%3C%3D%3E%3F%40ABCDEFGHIJKLMNOPQRSTUVWXYZ%5B%5C%5D%5E_%60abcdefghijklmnopqrstuvwxyz%7B%7C%7D%7E&BXsub=Submit
Copy previous line into clipboard

Basically, digits and letters (lower and upper case) come through as themselves, spaces come through as plus signs, while all other characters come through as a percent sign (%) followed by a hex representation of the character. Remembering that form controls are separated by ampersands (&), and each control's name is separated from its value by an equal sign (=), we're ready to write a decode function.

Writing the Decode Function

Start by changing the form action in testchars.cgi from stdin.cgi to decode.cgi, and copy stdin.cgi to decode.cgi, and of course make it read and execute for all. Test to make sure that everything still works the same.

Now add the decode function. Here's the English description of what it must do. First it must replace each plus sign with a space. Then it must replace each percent sign followed by two hex digits with the character whose ascii value is equal to the number defined by the two hex digits. Here's one way to do that.

Start with an empty return string. Split the incoming string into a list at percent signs. If the first character of the string is a percent sign, throw away the first list element. Otherwise copy the first element's string into the return string, and then throw away the first element. From this point forth, every list element's first two characters are a hex representation of a character, so for each append that char, and then append the rest of the element's string. Here's the code:
 
#!/usr/bin/perl

sub decode($)
  {
  $_[0] =~ s/\+/ /g;   ### Change + to space
  my(@parts) = split /%/, $_[0];
  my($returnstring) = "";

  (($_[0] =~ m/^\%/) ? (shift(@parts)) : ($returnstring = shift(@parts)));

  my($part);
  foreach $part (@parts)
    {
    $returnstring .= chr(hex(substr($part,0,2)));
    my($tail) = substr($part,2);
    $returnstring .= $tail if (defined($tail));
    }
  return($returnstring);
  }

print "Content-type: text/html\n\n";
print "Output of form. Copy next line into clipboard:<P>\n";
while(<STDIN>)
  {
  chomp($_);
  print decode($_);
  print "<br>\n";
  }
print "Copy previous line into clipboard<P>\n";

Notice in the preceding code that we coded the decode algorithm, and instead of printing the raw form output as in stdin.cgi, we run it through decode. The result is a string remarkably like the one typed in.

The preceding was only the lowest level of decoding. Form output inserts ampersands (&) to delineate controls (typically form fields and buttons), and within those controls, inserts equal signs (=) to separate the control's name from its data. What you really want to do is to use the form's output to populate a hash whose keys are control names and whose values are the controls' data values. Each of the values must be run through decode in order to
 

First separate the controls at the ampersands. Then for each control create a hash entry whose key is the control's name, and whose value is the decode of its value. The decode is simply to replace each plus sign with a  space, and for each percent sign followed by two hex digits, substitute the ascii character whose value is that hex digit. Here's decode.cgi, with function decode, which returns the control hash:


 [ Troubleshooters.com | Code Corner | Email Steve Litt ]

Copyright (C)1998 by Steve Litt -- Legal